﻿using Cemit.PolyProto;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Linq;

namespace Cemit.PolyServer.Lobby
{
    /// <summary>
    /// 大厅服务器
    /// </summary>
    public class LobbyServer : PolyServer, ILobbyServer
    {
        public static LobbyServer Instance { get; set; }

        private const short MAX_Match_FULL_NUMBER = 256;

        private Dictionary<short, Queue<Match>> matchesQueues;

        private readonly string gameServerIp;
        private readonly int gameServerPort;

        ClientState gameServer;

        public LobbyServer(string gameServerIp, int gameServerPort)
        {
            Instance = this;

            this.gameServerIp = gameServerIp;
            this.gameServerPort = gameServerPort;

            InstantiateMatchesQueues();

            Socket gameServerSocket = CreateTcpSocket();
            gameServerSocket.Connect(gameServerIp, gameServerPort);

            gameServer = new ClientState(gameServerSocket, this);

            AddSocketToSelectList(gameServer);

            Task.Run(async () => 
            {
                while (true)
                {
                    await Task.Delay(PingInterval * 500);
                    gameServer.Send(new Msg_Net_Ping());
                    gameServer.lastPingTime = Time.GetTimeStamp();
                }
            });
        }

        /// <summary>
        /// 初始化匹配队列字典
        /// </summary>
        private void InstantiateMatchesQueues()
        {
            matchesQueues = new Dictionary<short, Queue<Match>>();

            for (short i = 1; i <= MAX_Match_FULL_NUMBER; i++)
            {
                matchesQueues.Add(i, new Queue<Match>());
            }
        }

        public void JoinMatch(Player player, short fullPeople)
        {
            if (fullPeople < 1 || fullPeople > MAX_Match_FULL_NUMBER)
            {
                this.LogError($"请求匹配的人数超出最大限制！请求人数：{fullPeople} MAX：{MAX_Match_FULL_NUMBER}");
                return;
            }

            Match match = DequeueMatch();

            if (match == null)
            {
                match = new Match(fullPeople, GetMatchId());
            }

            this.Log($"{player.ID}加入匹配！");
            match.AddPlayer(player);

            if (match.IsFull)
            {
                //匹配完成
                MatchCompleted(match);
            }
            else
            {
                //重新加入队列
                EnqueueMatch();
            }

            void EnqueueMatch()
            {
                lock (matchesQueues[fullPeople])
                {
                    matchesQueues[fullPeople].Enqueue(match);
                }
            }

            string GetMatchId()
            {
                return string.Format(
                    "{0}-{1}",
                    Convert.ToString(fullPeople, 16),
                    Convert.ToString(DateTime.Now.ToFileTimeUtc(), 16));
            }

            Match DequeueMatch()
            {
                lock (matchesQueues[fullPeople])
                {
                    //新建匹配
                    if (matchesQueues[fullPeople].TryDequeue(out var ret))
                    {
                        return ret;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        //TODO 返回匹配成功消息
        private void MatchCompleted(Match match)
        {
            this.Log("匹配已完成: " + match.ID);

            MatchCountdown matchConfirm = new MatchCountdown(match, 20);
            matchConfirm.OnAllPlayerConfirmed += () => SendMatchSucceedToPlayers(match);
            matchConfirm.OnTimeout += () => SendMatchTimeoutToPlayers(match);

            foreach (var item in match.Players)
            {
                item.SendConfirm("confirm match", () => matchConfirm.Confirm(item));
            }

            matchConfirm.Start();
        }

        private void SendMatchTimeoutToPlayers(Match match)
        {
            match.Players.Send(new Msg_Lobby_MatchResult
            {
                MathResult = MatchResult.Timeout
            });
        }

        private async void SendMatchSucceedToPlayers(Match match)
        {
            Msg_Game_RoomId roomId = await GetRoomId(match);

            //向所有玩家发送匹配完成
            match.Players.Send(new Msg_Lobby_MatchResult()
            {
                GameRoomInfo = GetRoomInfo(match, roomId),
                MathResult = MatchResult.Successful
            });
        }

        private GameRoomInfo GetRoomInfo(Match match, Msg_Game_RoomId roomId)
        {
            GameRoomInfo roomInfo = new GameRoomInfo
            {
                Ip = gameServerIp,
                Port = gameServerPort,
                RoomId = roomId.Index
            };

            foreach (var item in match.Players)
            {
                roomInfo.PlayerIds.Add(item.ID);
            }

            return roomInfo;
        }

        private async Task<Msg_Game_RoomId> GetRoomId(Match match)
        {
            //TODO: 转移到游戏服务器调度器中

            //获取空余游戏服务器
            //string ip = gameServerDispatcher.Send(new Msg_GSD_GetGameServer());

            Msg_Game_CreateRoom createRoomMsg = new Msg_Game_CreateRoom();
            foreach (var item in match.Players)
            {
                createRoomMsg.Player.Add(item.ID);
            }

            // 向游戏服务器申请新建一个房间
            Msg_Game_RoomId roomId = await gameServer.Get<Msg_Game_RoomId>(createRoomMsg);
            return roomId;
        }
    }
}
